gtk: Rework pointer cursor selection
authorCarlos Garnacho <carlosg@gnome.org>
Wed, 24 May 2017 23:45:18 +0000 (01:45 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Thu, 25 May 2017 14:25:59 +0000 (16:25 +0200)
Check the grab widget (both explicit and implicit) and check for a cursor
from the target widget up to this grab widget. If the target widget is
outside the grab widget, only the grab wigdet's cursor will be checked.

This also means that we have to ensure the cursor is updated on button
releases, as an implicit grab being deactivated must trigger a cursor
lookup from the target widget.

gtk/gtkmain.c
gtk/gtkwindow.c

index 209bb5f228de4f75cf3d1d464fd140a26c0db638..5ca3729471cfc32910cad77243cc0a343d43acb4 100644 (file)
@@ -1498,7 +1498,7 @@ handle_pointing_event (GdkEvent *event)
       target = _gtk_toplevel_pick (toplevel, x, y, NULL, NULL);
       old_target = update_pointer_focus_state (toplevel, event, target);
       if (event->type == GDK_MOTION_NOTIFY || event->type == GDK_ENTER_NOTIFY)
-        gtk_window_maybe_update_cursor (toplevel, target, device);
+        gtk_window_maybe_update_cursor (toplevel, NULL, device);
 
       if (event->type == GDK_TOUCH_BEGIN)
         gtk_window_set_pointer_focus_grab (toplevel, device, sequence, target);
@@ -1516,6 +1516,9 @@ handle_pointing_event (GdkEvent *event)
       gtk_window_set_pointer_focus_grab (toplevel, device, sequence,
                                          event->type == GDK_BUTTON_PRESS ?
                                          target : NULL);
+
+      if (event->type == GDK_BUTTON_RELEASE)
+        gtk_window_maybe_update_cursor (toplevel, NULL, device);
       break;
     case GDK_SCROLL:
     case GDK_TOUCHPAD_PINCH:
index 0a01ac8a140ec9d8850804626f078e4c878ddf29..1f7e3d84d3d0faaed87d8ed9895e8569da27e6ea 100644 (file)
@@ -11432,15 +11432,31 @@ gtk_window_set_pointer_focus_grab (GtkWindow        *window,
 static void
 update_cursor (GtkWindow *toplevel,
                GdkDevice *device,
+               GtkWidget *grab_widget,
                GtkWidget *target)
 {
   GdkCursor *cursor = NULL;
   GList *widgets = NULL, *l;
 
-  while (target)
+  if (grab_widget && !gtk_widget_is_ancestor (target, grab_widget))
     {
-      widgets = g_list_prepend (widgets, target);
-      target = _gtk_widget_get_parent (target);
+      /* Outside the grab widget, cursor stays to whatever the grab
+       * widget says.
+       */
+      widgets = g_list_prepend (widgets, grab_widget);
+    }
+  else
+    {
+      /* Inside the grab widget or in absence of grabs, allow walking
+       * up the hierarchy to find out the cursor.
+       */
+      while (target)
+        {
+          widgets = g_list_prepend (widgets, target);
+          if (grab_widget && target == grab_widget)
+            break;
+          target = _gtk_widget_get_parent (target);
+        }
     }
 
   for (l = widgets; l; l = l->next)
@@ -11465,17 +11481,38 @@ gtk_window_maybe_update_cursor (GtkWindow *window,
   for (l = window->priv->foci; l; l = l->next)
     {
       GtkPointerFocus *focus = l->data;
+      GtkWidget *grab_widget, *target;
+      GtkWindowGroup *group;
 
       if (focus->sequence)
         continue;
       if (device && device != focus->device)
         continue;
 
-      if (widget != focus->target &&
-          !gtk_widget_is_ancestor (focus->target, widget))
-        continue;
+      group = gtk_window_get_group (window);
+      grab_widget = gtk_window_group_get_current_device_grab (group,
+                                                              focus->device);
+      if (!grab_widget)
+        grab_widget = gtk_window_group_get_current_grab (group);
+      if (!grab_widget)
+        grab_widget = gtk_pointer_focus_get_implicit_grab (focus);
+
+      target = gtk_pointer_focus_get_target (focus);
+
+      if (widget)
+        {
+          /* Check whether the changed widget affects the current cursor
+           * lookups.
+           */
+          if (grab_widget && grab_widget != widget &&
+              !gtk_widget_is_ancestor (widget, grab_widget))
+            continue;
+          if (grab_widget != widget &&
+              !gtk_widget_is_ancestor (target, widget))
+            continue;
+        }
 
-      update_cursor (focus->toplevel, focus->device, focus->target);
+      update_cursor (focus->toplevel, focus->device, grab_widget, target);
 
       if (device)
         break;